;---------------------------------------------------------;
;                                                         ;
; very low level graphics routines.                       ;
; Things that have to be FAST can be found here.          ;
;                                                         ;
; [c]copyright 1996 by AlphaHelix                         ;
;                                                         ;
;---------------------------------------------------------;


        IDEAL
        P486

        model   flat, c


	dataseg
include "xlib.ash"

CRISPYVALUES    equ     17*4
label           _crispy dword
; oans.
                dd      0ffffffffh, 0ffff0000h, 0ffffffffh, 00000ff00h
                dd      0ffffffffh, 00000ffffh, 0ffff0000h, 0ffffffffh
                dd      0ffffffffh, 000ffff00h, 0ffffffffh, 0ffffffffh
                dd      0ff000000h, 0ffffffffh, 0ffffffffh, 0ff000000h
                dd      0ffffffffh
; zwoa.
                dd      0ffffffffh, 000000000h, 0ffffffffh, 000000000h
                dd      0ffffffffh, 000ff00ffh, 000000000h, 0ffffffffh
                dd      0ff00ff00h, 0ffffffffh, 0000000ffh, 0ffffffffh
                dd      000000000h, 0ffffffffh, 000ffff00h, 0ffffffffh
                dd      000000000h
; drue.
                dd      0ffffffffh, 000000000h, 0ff00ff00h, 000000000h
                dd      0ffffffffh, 000ff00ffh, 000000000h, 0ffffffffh
                dd      0ff000000h, 0ffff0000h, 000000000h, 000ffff00h
                dd      000000000h, 0ffffffffh, 000000000h, 000ff00ffh
                dd      000000000h
; viere.
                dd      0ffffffffh, 000000000h, 0ff00ff00h, 000000000h
                dd      0ffffffffh, 0ff00ff00h, 000000000h, 0ff00ff00h
                dd      000000000h, 000ff00ffh, 000000000h, 000ffff00h
                dd      0ffffffffh, 000000000h, 0000000ffh, 00000ffffh
                dd      000000000h
; fuenfe.
                dd      0ffffffffh, 000000000h, 000000000h, 000000000h
                dd      0ff00ff00h, 000000000h, 000000000h, 000ff00ffh
                dd      000000000h, 000000000h, 0ffffffffh, 000000000h
                dd      000000000h, 0ff00ff00h, 000000000h, 0000000ffh
                dd      000000000h
; sexe laeute.
                dd      0ffffffffh, 000000000h, 000000000h, 000000000h
                dd      000000000h, 000000000h, 000000000h, 000ff00ffh
                dd      000000000h, 000000000h, 0ff000000h, 000000000h
                dd      0ffffffffh, 000000000h, 000000000h, 000000000h
                dd      000000000h
; sebene
                dd      000ff00ffh, 000000000h, 000000000h, 000000000h
                dd      000000000h, 000000000h, 000000000h, 000000000h
                dd      0ff00ff00h, 000000000h, 000000000h, 000000000h
                dd      0000000ffh, 000000000h, 000000000h, 000000000h
                dd      000000000h
; acht
                dd      000000000h, 000000000h, 000000000h, 000000000h
                dd      000000000h, 000000000h, 000000000h, 000000000h
                dd      000000000h, 000000000h, 000000000h, 000000000h
                dd      000000000h, 000000000h, 000000000h, 000000000h
                dd      000000000h

crispy          dd      ?
crispylow       dd      ?
crispyhi        dd      ?


	codeseg

; Sprite rountines.
        public  x_drawsprite
        public  x_drawvanilla
        public  x_drawshadow
        public  x_drawcrispy

; Tile handling rountines.
        public  x_layer0
        public  x_layer1


; ############## Code ###############

;----------------------------------------------------------
; x_drawsprite(void *sprite, int x, int y, int n);
;----------------------------------------------------------
proc    x_drawsprite nolanguage

STACKSIZE       equ     14h
; Setup Stack Frame
        sub     esp, STACKSIZE  ; reserve space for local vriables.
        push    esi
        push    edi
        push    ebp
SAVE            equ     0ch     ; Number of bytes needed by "PUSHes"
; Define local variables access equates.
space   equ     dword esp+00h+SAVE
ysn     equ     dword esp+04h+SAVE
yn      equ     dword esp+08h+SAVE
xsn     equ     dword esp+0ch+SAVE
xn      equ     dword esp+10h+SAVE
; Parameter access equates.
sprite  equ     dword esp+04h+SAVE+STACKSIZE
_x      equ     dword esp+08h+SAVE+STACKSIZE
_y      equ     dword esp+0ch+SAVE+STACKSIZE
n       equ     dword esp+10h+SAVE+STACKSIZE

; Start of cool code.
        mov     esi, [sprite]   ; Get pointer to sprite.

; Clipping x coordinate
        mov     eax, [_x]
        mov     edx, [(Sprite ptr esi).@Sprite@xs_data]
        cmp     eax, -BORDER
        jge     @@x1
        neg     eax
        sub     edx, eax
        jl      @@exit
        mov     ebx, eax
        dec     ebx
        shr     ebx, 2
        and     ebx, 0ffffch
        mov     [space], ebx
        neg     eax
        and     eax, 0fh
        mov     [xn], eax
        sub     edx, eax
        add     edx, BORDER
        mov     [xsn], edx
        jmp     @@ycheck
@@x1:
        mov     ecx, XMAX
        sub     ecx, eax
        cmp     edx, ecx
        jle     @@x2
        cmp     ecx, 0
        jle     @@exit
        add     ecx, BORDER-1
        add     eax, BORDER
        mov     [xn], eax
        and     ecx, 0fff0h
        mov     [xsn], ecx
        sub     edx, ecx
        sub     ebx, ebx
        shr     edx, 2
        mov     [space], edx
        jmp     @@ycheck
@@x2:
        add     eax, BORDER
        mov     [xn], eax
        mov     [xsn], edx
        mov     [space], 0
        xor     ebx, ebx

; Clipping y coordinate
@@ycheck:
        mov     eax, [_y]
        cmp     eax, 0
        jge     @@y1
        neg     eax
        mov     edx, [(Sprite ptr esi).@Sprite@ys_data]
        cmp     eax, edx
        jge     @@exit
        sub     edx, eax
        mov     [ysn], edx
        imul    eax, [(Sprite ptr esi).@Sprite@xs_data]
        add     ebx, eax
        mov     [yn], 0
        jmp     @@done
@@y1:
        mov     ecx, eax
        mov     edx, [(Sprite ptr esi).@Sprite@ys_data]
        add     ecx, edx
        mov     edi, YMAX
        cmp     ecx, edi
        jle     @@y2
        cmp     eax, edi
        jge     @@exit
        mov     [yn], eax
        sub     edi, eax
        mov     [ysn], edi
        jmp     @@done
@@y2:
        mov     [yn], eax
        mov     [ysn], edx

@@done:

; Loop initialization.
        mov     eax, [(Sprite ptr esi).@Sprite@fsize]
        imul    eax, [n]
        lea     esi, [(Sprite ptr esi).@Sprite@data]
        add     esi, eax
        add     esi, ebx

        mov     ecx, [xn]
        mov     ebx, ecx
        mov     eax, ebx        ; Load eax for later use.
        and     ecx, 12
        shl     ecx, 1          ; cl holds initial shift value now.
        and     ebx, 3
        imul    ebx, PLANESIZE  ; ebx holds plane offset.

        mov     ch, [byte ysn]  ; Set outer loop count register.
; Calculate offset into screen.
        mov     edi, [yn]
        imul    edi, LINEBYTES
        add     edi, [_vscreen]
        shr     eax, 2
        and     eax, 0ffffch
        add     edi, eax

; We are ready to go.
; Registers are setup like this:
; eax, edx: general usable registers.
; ecx     : counter and shift values.
; esi     : pointer to sprite data.
; edi+ebx : pointer to destination in vscreen.
; ebp     : overshift value.

@@outloop:
        and     ebx, 0ffffffe0h
; Copy saved SHIFT value to active SHIFT value.
        mov     eax, ecx
        rol     ecx, 16
        mov     cl, al

rept    4
local   @@inloop, @@skip1
local   @@n10, @@n11, @@n12, @@n13
local   @@n20, @@n21, @@n22, @@n23

        xor     ebp, ebp

        mov     edx, [xsn]
        shr     edx, 4
        mov     ch, dl

@@inloop:
        mov     eax, [esi]
        add     esi, 4
        sub     edx, edx
        shld    edx, eax, cl
        shl     eax, cl
        or      eax, ebp
        mov     ebp, edx

; eax to screen
        mov     edx, [edi+ebx]          ; Load background data.
; Check for transparency.
        or      al, al
        jz      @@n10
        mov     dl, al
@@n10:
        or      ah, ah
        jz      @@n11
        mov     dh, ah
@@n11:
        ror     eax, 16
        ror     edx, 16
        or      al, al
        jz      @@n12
        mov     dl, al
@@n12:
        or      ah, ah
        jz      @@n13
        mov     dh, ah
@@n13:
        ror     edx, 16
        mov     [edi+ebx], edx
        add     edi, 4

        dec     ch
        jnz     @@inloop

        add     esi, [space]

; ebp to screen
        mov     eax, ebp
        mov     edx, [edi+ebx]          ; Load background data.
; Check for transparency.
        or      al, al
        jz      @@n20
        mov     dl, al
@@n20:
        or      ah, ah
        jz      @@n21
        mov     dh, ah
@@n21:
        ror     eax, 16
        ror     edx, 16
        or      al, al
        jz      @@n22
        mov     dl, al
@@n22:
        or      ah, ah
        jz      @@n23
        mov     dh, ah
@@n23:
        ror     edx, 16
        mov     [edi+ebx], edx

; Reset pointer for next sweep.
        mov     edx, [xsn]
        shr     edx, 2
        sub     edi, edx

        add     ebx, PLANESIZE
        cmp     ebx, 4*PLANESIZE
        jb      @@skip1
        sub     ebx, 4*PLANESIZE
        add     cl, 8
        and     cl, 31
        jnz     @@skip1
        add     ebx, 4
@@skip1:
endm
; end of lall
        add     edi, LINEBYTES
        rol     ecx, 16
        dec     ch
        jnz     @@outloop

; clean up
@@exit:
        pop     ebp
        pop     edi
        pop     esi
        add     esp, STACKSIZE
        ret

endp    x_drawsprite


;----------------------------------------------------------
; x_drawshadow(void *sprite, int x, int y, int n);
;----------------------------------------------------------
proc    x_drawshadow nolanguage

STACKSIZE       equ     18h
; Setup Stack Frame
        sub     esp, STACKSIZE  ; reserve space for local vriables.
        push    esi
        push    edi
        push    ebp
SAVE            equ     0ch     ; Number of bytes needed by "PUSHes"
; Define local variables access equates.
space   equ     dword esp+00h+SAVE
ysn     equ     dword esp+04h+SAVE
yn      equ     dword esp+08h+SAVE
xsn     equ     dword esp+0ch+SAVE
xn      equ     dword esp+10h+SAVE
ecxsave equ     dword esp+14h+SAVE
; Parameter access equates.
sprite  equ     dword esp+04h+SAVE+STACKSIZE
_x      equ     dword esp+08h+SAVE+STACKSIZE
_y      equ     dword esp+0ch+SAVE+STACKSIZE
n       equ     dword esp+10h+SAVE+STACKSIZE

; Start of cool code.
        mov     esi, [sprite]   ; Get pointer to sprite.

; Clipping x coordinate
        mov     eax, [_x]
        mov     edx, [(Sprite ptr esi).@Sprite@xs_data]
        cmp     eax, -BORDER
        jge     @@x1
        neg     eax
        sub     edx, eax
        jl      @@exit
        mov     ebx, eax
        dec     ebx
        shr     ebx, 2
        and     ebx, 0ffffch
        mov     [space], ebx
        neg     eax
        and     eax, 0fh
        mov     [xn], eax
        sub     edx, eax
        add     edx, BORDER
        mov     [xsn], edx
        jmp     @@ycheck
@@x1:
        mov     ecx, XMAX
        sub     ecx, eax
        cmp     edx, ecx
        jle     @@x2
        cmp     ecx, 0
        jle     @@exit
        add     ecx, BORDER-1
        add     eax, BORDER
        mov     [xn], eax
        and     ecx, 0fff0h
        mov     [xsn], ecx
        sub     edx, ecx
        sub     ebx, ebx
        shr     edx, 2
        mov     [space], edx
        jmp     @@ycheck
@@x2:
        add     eax, BORDER
        mov     [xn], eax
        mov     [xsn], edx
        mov     [space], 0
        xor     ebx, ebx

; Clipping y coordinate
@@ycheck:
        mov     eax, [_y]
        cmp     eax, 0
        jge     @@y1
        neg     eax
        mov     edx, [(Sprite ptr esi).@Sprite@ys_data]
        cmp     eax, edx
        jge     @@exit
        sub     edx, eax
        mov     [ysn], edx
        imul    eax, [(Sprite ptr esi).@Sprite@xs_data]
        add     ebx, eax
        mov     [yn], 0
        jmp     @@done
@@y1:
        mov     ecx, eax
        mov     edx, [(Sprite ptr esi).@Sprite@ys_data]
        add     ecx, edx
        mov     edi, YMAX
        cmp     ecx, edi
        jle     @@y2
        cmp     eax, edi
        jge     @@exit
        mov     [yn], eax
        sub     edi, eax
        mov     [ysn], edi
        jmp     @@done
@@y2:
        mov     [yn], eax
        mov     [ysn], edx

@@done:

; Loop initialization.
        mov     eax, [(Sprite ptr esi).@Sprite@fsize]
        imul    eax, [n]
        lea     esi, [(Sprite ptr esi).@Sprite@data]
        add     esi, eax
        add     esi, ebx

        mov     ecx, [xn]
        mov     ebx, ecx
        mov     eax, ebx        ; Load eax for later use.
        and     ecx, 12
        shl     ecx, 1          ; cl holds initial shift value now.
        and     ebx, 3
        imul    ebx, PLANESIZE  ; ebx holds plane offset.

        mov     ch, [byte ysn]  ; Set outer loop count register.
; Calculate offset into screen.
        mov     edi, [yn]
        imul    edi, LINEBYTES
        add     edi, [_vscreen]
        shr     eax, 2
        and     eax, 0ffffch
        add     edi, eax

; We are ready to go.
; Registers are setup like this:
; eax, edx: general usable registers.
; ecx     : counter and shift values.
; esi     : pointer to sprite data.
; edi+ebx : pointer to destination in vscreen.
; ebp     : overshift value.

@@outloop:
        and     ebx, 0ffffffe0h
; Copy saved SHIFT value to active SHIFT value.
        mov     eax, ecx
        rol     ecx, 16
        mov     cl, al

rept    4
local   @@inloop, @@skip1
local   @@n10, @@n11, @@n12, @@n13
local   @@n20, @@n21, @@n22, @@n23

        xor     ebp, ebp

        mov     edx, [xsn]
        shr     edx, 4
        mov     ch, dl

@@inloop:
        mov     eax, [esi]
        add     esi, 4
        sub     edx, edx
        shld    edx, eax, cl
        shl     eax, cl
        mov     [ecxsave], ecx          ; To free another register.
        or      eax, ebp
        mov     ebp, edx

; eax to screen
        mov     edx, [edi+ebx]          ; Load background data.
        sub     ecx, ecx
; Check for transparency.
        or      al, al
        jz      @@n10
        mov     cl, dl
        mov     dl, [byte _shadow+ecx]
@@n10:
        or      ah, ah
        jz      @@n11
        mov     cl, dh
        mov     dh, [byte _shadow+ecx]
@@n11:
        ror     eax, 16
        ror     edx, 16
        or      al, al
        jz      @@n12
        mov     cl, dl
        mov     dl, [byte _shadow+ecx]
@@n12:
        or      ah, ah
        jz      @@n13
        mov     cl, dh
        mov     dh, [byte _shadow+ecx]
@@n13:
        ror     edx, 16
        mov     [edi+ebx], edx
        add     edi, 4

        mov     ecx, [ecxsave]          ; Well, well. I just can't do better.
        dec     ch
        jnz     @@inloop

        add     esi, [space]

; ebp to screen
        mov     [ecxsave], ecx
        mov     eax, ebp
        mov     edx, [edi+ebx]          ; Load background data.
        sub     ecx, ecx
; Check for transparency.
        or      al, al
        jz      @@n20
        mov     cl, dl
        mov     dl, [byte _shadow+ecx]
@@n20:
        or      ah, ah
        jz      @@n21
        mov     cl, dh
        mov     dh, [byte _shadow+ecx]
@@n21:
        ror     eax, 16
        ror     edx, 16
        or      al, al
        jz      @@n22
        mov     cl, dl
        mov     dl, [byte _shadow+ecx]
@@n22:
        or      ah, ah
        jz      @@n23
        mov     cl, dh
        mov     dh, [byte _shadow+ecx]
@@n23:
        ror     edx, 16
        mov     [edi+ebx], edx

; Reset pointer for next sweep.
        mov     edx, [xsn]
        shr     edx, 2
        sub     edi, edx
        mov     ecx, [ecxsave]

        add     ebx, PLANESIZE
        cmp     ebx, 4*PLANESIZE
        jb      @@skip1
        sub     ebx, 4*PLANESIZE
        add     cl, 8
        and     cl, 31
        jnz     @@skip1
        add     ebx, 4
@@skip1:
endm
; end of lall
        add     edi, LINEBYTES
        rol     ecx, 16
        dec     ch
        jnz     @@outloop

; clean up
@@exit:
        pop     ebp
        pop     edi
        pop     esi
        add     esp, STACKSIZE
        ret

endp    x_drawshadow


;----------------------------------------------------------
; x_drawvanilla(void *sprite, int x, int y, int n, int c);
;----------------------------------------------------------
proc    x_drawvanilla nolanguage

STACKSIZE       equ     14h
; Setup Stack Frame
        sub     esp, STACKSIZE  ; reserve space for local vriables.
        push    esi
        push    edi
        push    ebp
SAVE            equ     0ch     ; Number of bytes needed by "PUSHes"
; Define local variables access equates.
space   equ     dword esp+00h+SAVE
ysn     equ     dword esp+04h+SAVE
yn      equ     dword esp+08h+SAVE
xsn     equ     dword esp+0ch+SAVE
xn      equ     dword esp+10h+SAVE
; Parameter access equates.
sprite  equ     dword esp+04h+SAVE+STACKSIZE
_x      equ     dword esp+08h+SAVE+STACKSIZE
_y      equ     dword esp+0ch+SAVE+STACKSIZE
n       equ     dword esp+10h+SAVE+STACKSIZE
c       equ     dword esp+14h+SAVE+STACKSIZE

; Start of cool code.
        mov     esi, [sprite]   ; Get pointer to sprite.

; Clipping x coordinate
        mov     eax, [_x]
        mov     edx, [(Sprite ptr esi).@Sprite@xs_data]
        cmp     eax, -BORDER
        jge     @@x1
        neg     eax
        sub     edx, eax
        jl      @@exit
        mov     ebx, eax
        dec     ebx
        shr     ebx, 2
        and     ebx, 0ffffch
        mov     [space], ebx
        neg     eax
        and     eax, 0fh
        mov     [xn], eax
        sub     edx, eax
        add     edx, BORDER
        mov     [xsn], edx
        jmp     @@ycheck
@@x1:
        mov     ecx, XMAX
        sub     ecx, eax
        cmp     edx, ecx
        jle     @@x2
        cmp     ecx, 0
        jle     @@exit
        add     ecx, BORDER-1
        add     eax, BORDER
        mov     [xn], eax
        and     ecx, 0fff0h
        mov     [xsn], ecx
        sub     edx, ecx
        sub     ebx, ebx
        shr     edx, 2
        mov     [space], edx
        jmp     @@ycheck
@@x2:
        add     eax, BORDER
        mov     [xn], eax
        mov     [xsn], edx
        mov     [space], 0
        xor     ebx, ebx

; Clipping y coordinate
@@ycheck:
        mov     eax, [_y]
        cmp     eax, 0
        jge     @@y1
        neg     eax
        mov     edx, [(Sprite ptr esi).@Sprite@ys_data]
        cmp     eax, edx
        jge     @@exit
        sub     edx, eax
        mov     [ysn], edx
        imul    eax, [(Sprite ptr esi).@Sprite@xs_data]
        add     ebx, eax
        mov     [yn], 0
        jmp     @@done
@@y1:
        mov     ecx, eax
        mov     edx, [(Sprite ptr esi).@Sprite@ys_data]
        add     ecx, edx
        mov     edi, YMAX
        cmp     ecx, edi
        jle     @@y2
        cmp     eax, edi
        jge     @@exit
        mov     [yn], eax
        sub     edi, eax
        mov     [ysn], edi
        jmp     @@done
@@y2:
        mov     [yn], eax
        mov     [ysn], edx

@@done:

; Loop initialization.
        mov     eax, [(Sprite ptr esi).@Sprite@fsize]
        imul    eax, [n]
        lea     esi, [(Sprite ptr esi).@Sprite@data]
        add     esi, eax
        add     esi, ebx

        mov     ecx, [xn]
        mov     ebx, ecx
        mov     eax, ebx        ; Load eax for later use.
        and     ecx, 12
        shl     ecx, 1          ; cl holds initial shift value now.
        and     ebx, 3
        imul    ebx, PLANESIZE  ; ebx holds plane offset.

        mov     ch, [byte ysn]  ; Set outer loop count register.
; Calculate offset into screen.
        mov     edi, [yn]
        imul    edi, LINEBYTES
        add     edi, [_vscreen]
        shr     eax, 2
        and     eax, 0ffffch
        add     edi, eax

; We are ready to go.
; Registers are setup like this:
; eax, edx: general usable registers.
; ecx     : counter and shift values.
; esi     : pointer to sprite data.
; edi+ebx : pointer to destination in vscreen.
; ebp     : overshift value.

@@outloop:
        and     ebx, 0ffffffe0h
; Copy saved SHIFT value to active SHIFT value.
        mov     eax, ecx
        rol     ecx, 16
        mov     cl, al

rept    4
local   @@inloop, @@skip1
local   @@n10, @@n11, @@n12, @@n13
local   @@n20, @@n21, @@n22, @@n23

        xor     ebp, ebp

        mov     edx, [xsn]
        shr     edx, 4
        mov     ch, dl

@@inloop:
        mov     eax, [esi]
        add     esi, 4
        sub     edx, edx
        shld    edx, eax, cl
        shl     eax, cl
        or      eax, ebp
        mov     ebp, edx

; eax to screen
        mov     edx, [edi+ebx]          ; Load background data.
; Check for transparency.
        or      al, al
        jz      @@n10
        mov     dl, [byte c]
@@n10:
        or      ah, ah
        jz      @@n11
        mov     dh, [byte c]
@@n11:
        ror     eax, 16
        ror     edx, 16
        or      al, al
        jz      @@n12
        mov     dl, [byte c]
@@n12:
        or      ah, ah
        jz      @@n13
        mov     dh, [byte c]
@@n13:
        ror     edx, 16
        mov     [edi+ebx], edx
        add     edi, 4

        dec     ch
        jnz     @@inloop

        add     esi, [space]

; ebp to screen
        mov     eax, ebp
        mov     edx, [edi+ebx]          ; Load background data.
; Check for transparency.
        or      al, al
        jz      @@n20
        mov     dl, [byte c]
@@n20:
        or      ah, ah
        jz      @@n21
        mov     dh, [byte c]
@@n21:
        ror     eax, 16
        ror     edx, 16
        or      al, al
        jz      @@n22
        mov     dl, [byte c]
@@n22:
        or      ah, ah
        jz      @@n23
        mov     dh, [byte c]
@@n23:
        ror     edx, 16
        mov     [edi+ebx], edx

; Reset pointer for next sweep.
        mov     edx, [xsn]
        shr     edx, 2
        sub     edi, edx

        add     ebx, PLANESIZE
        cmp     ebx, 4*PLANESIZE
        jb      @@skip1
        sub     ebx, 4*PLANESIZE
        add     cl, 8
        and     cl, 31
        jnz     @@skip1
        add     ebx, 4
@@skip1:
endm
; end of lall
        add     edi, LINEBYTES
        rol     ecx, 16
        dec     ch
        jnz     @@outloop

; clean up
@@exit:
        pop     ebp
        pop     edi
        pop     esi
        add     esp, STACKSIZE
        ret

endp    x_drawvanilla


;----------------------------------------------------------
; x_drawcrispy(void *sprite, int x, int y, int n, int c);
;----------------------------------------------------------
proc    x_drawcrispy nolanguage

STACKSIZE       equ     14h
; Setup Stack Frame
        sub     esp, STACKSIZE  ; reserve space for local vriables.
        push    esi
        push    edi
        push    ebp
SAVE            equ     0ch     ; Number of bytes needed by "PUSHes"
; Define local variables access equates.
space   equ     dword esp+00h+SAVE
ysn     equ     dword esp+04h+SAVE
yn      equ     dword esp+08h+SAVE
xsn     equ     dword esp+0ch+SAVE
xn      equ     dword esp+10h+SAVE
; Parameter access equates.
sprite  equ     dword esp+04h+SAVE+STACKSIZE
_x      equ     dword esp+08h+SAVE+STACKSIZE
_y      equ     dword esp+0ch+SAVE+STACKSIZE
n       equ     dword esp+10h+SAVE+STACKSIZE
c       equ     dword esp+14h+SAVE+STACKSIZE

; Start of cool code.
; Setup crispy data.
        mov     eax, [c]
        imul    eax, CRISPYVALUES
        add     eax, offset _crispy
        mov     [crispy], eax
        mov     [crispylow], eax
        add     eax, CRISPYVALUES
        mov     [crispyhi], eax

        mov     esi, [sprite]   ; Get pointer to sprite.

; Clipping x coordinate
        mov     eax, [_x]
        mov     edx, [(Sprite ptr esi).@Sprite@xs_data]
        cmp     eax, -BORDER
        jge     @@x1
        neg     eax
        sub     edx, eax
        jl      @@exit
        mov     ebx, eax
        dec     ebx
        shr     ebx, 2
        and     ebx, 0ffffch
        mov     [space], ebx
        neg     eax
        and     eax, 0fh
        mov     [xn], eax
        sub     edx, eax
        add     edx, BORDER
        mov     [xsn], edx
        jmp     @@ycheck
@@x1:
        mov     ecx, XMAX
        sub     ecx, eax
        cmp     edx, ecx
        jle     @@x2
        cmp     ecx, 0
        jle     @@exit
        add     ecx, BORDER-1
        add     eax, BORDER
        mov     [xn], eax
        and     ecx, 0fff0h
        mov     [xsn], ecx
        sub     edx, ecx
        sub     ebx, ebx
        shr     edx, 2
        mov     [space], edx
        jmp     @@ycheck
@@x2:
        add     eax, BORDER
        mov     [xn], eax
        mov     [xsn], edx
        mov     [space], 0
        xor     ebx, ebx

; Clipping y coordinate
@@ycheck:
        mov     eax, [_y]
        cmp     eax, 0
        jge     @@y1
        neg     eax
        mov     edx, [(Sprite ptr esi).@Sprite@ys_data]
        cmp     eax, edx
        jge     @@exit
        sub     edx, eax
        mov     [ysn], edx
        imul    eax, [(Sprite ptr esi).@Sprite@xs_data]
        add     ebx, eax
        mov     [yn], 0
        jmp     @@done
@@y1:
        mov     ecx, eax
        mov     edx, [(Sprite ptr esi).@Sprite@ys_data]
        add     ecx, edx
        mov     edi, YMAX
        cmp     ecx, edi
        jle     @@y2
        cmp     eax, edi
        jge     @@exit
        mov     [yn], eax
        sub     edi, eax
        mov     [ysn], edi
        jmp     @@done
@@y2:
        mov     [yn], eax
        mov     [ysn], edx

@@done:

; Loop initialization.
        mov     eax, [(Sprite ptr esi).@Sprite@fsize]
        imul    eax, [n]
        lea     esi, [(Sprite ptr esi).@Sprite@data]
        add     esi, eax
        add     esi, ebx

        mov     ecx, [xn]
        mov     ebx, ecx
        mov     eax, ebx        ; Load eax for later use.
        and     ecx, 12
        shl     ecx, 1          ; cl holds initial shift value now.
        and     ebx, 3
        imul    ebx, PLANESIZE  ; ebx holds plane offset.

        mov     ch, [byte ysn]  ; Set outer loop count register.
; Calculate offset into screen.
        mov     edi, [yn]
        imul    edi, LINEBYTES
        add     edi, [_vscreen]
        shr     eax, 2
        and     eax, 0ffffch
        add     edi, eax

; We are ready to go.
; Registers are setup like this:
; eax, edx: general usable registers.
; ecx     : counter and shift values.
; esi     : pointer to sprite data.
; edi+ebx : pointer to destination in vscreen.
; ebp     : overshift value.

@@outloop:
        and     ebx, 0ffffffe0h
; Copy saved SHIFT value to active SHIFT value.
        mov     eax, ecx
        rol     ecx, 16
        mov     cl, al

rept    4
local   @@crispy1, @@crispy2
local   @@inloop, @@skip1
local   @@n10, @@n11, @@n12, @@n13
local   @@n20, @@n21, @@n22, @@n23

        xor     ebp, ebp

        mov     edx, [xsn]
        shr     edx, 4
        mov     ch, dl

@@inloop:
        mov     eax, [esi]              ; Load foreground data.
        add     esi, 4
        sub     edx, edx
        shld    edx, eax, cl
        shl     eax, cl
        or      eax, ebp
        mov     ebp, edx

; Add some crispy.
        mov     edx, [crispy]           ; Get current crispy pointer.
        add     edx, 4                  ; Go to the next crispy entry.
        cmp     edx, [crispyhi]         ; Compare to upper limit.
        jb      @@crispy1
        mov     edx, [crispylow]        ; Wrap around to lower bound.
@@crispy1:
        mov     [crispy], edx
        mov     edx, [edx]
        and     eax, edx                ; DO CRISPY.

; eax to screen
        mov     edx, [edi+ebx]          ; Load background data.
; Check for transparency.
        or      al, al
        jz      @@n10
        mov     dl, al
@@n10:
        or      ah, ah
        jz      @@n11
        mov     dh, ah
@@n11:
        ror     eax, 16
        ror     edx, 16
        or      al, al
        jz      @@n12
        mov     dl, al
@@n12:
        or      ah, ah
        jz      @@n13
        mov     dh, ah
@@n13:
        ror     edx, 16
        mov     [edi+ebx], edx
        add     edi, 4

        dec     ch
        jnz     @@inloop

        add     esi, [space]

; ebp to screen
        mov     eax, ebp

; Add some crispy.
        mov     edx, [crispy]           ; Get current crispy pointer.
        add     edx, 4                  ; Go to the next crispy entry.
        cmp     edx, [crispyhi]         ; Compare to upper limit.
        jb      @@crispy2
        mov     edx, [crispylow]        ; Wrap around to lower bound.
@@crispy2:
        mov     [crispy], edx
        mov     edx, [edx]
        and     eax, edx                ; DO CRISPY.

        mov     edx, [edi+ebx]          ; Load background data.
; Check for transparency.
        or      al, al
        jz      @@n20
        mov     dl, al
@@n20:
        or      ah, ah
        jz      @@n21
        mov     dh, ah
@@n21:
        ror     eax, 16
        ror     edx, 16
        or      al, al
        jz      @@n22
        mov     dl, al
@@n22:
        or      ah, ah
        jz      @@n23
        mov     dh, ah
@@n23:
        ror     edx, 16
        mov     [edi+ebx], edx

; Reset pointer for next sweep.
        mov     edx, [xsn]
        shr     edx, 2
        sub     edi, edx

        add     ebx, PLANESIZE
        cmp     ebx, 4*PLANESIZE
        jb      @@skip1
        sub     ebx, 4*PLANESIZE
        add     cl, 8
        and     cl, 31
        jnz     @@skip1
        add     ebx, 4
@@skip1:
endm
; end of lall
        add     edi, LINEBYTES
        rol     ecx, 16
        dec     ch
        jnz     @@outloop

; clean up
@@exit:
        pop     ebp
        pop     edi
        pop     esi
        add     esp, STACKSIZE
        ret

endp    x_drawcrispy



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Start of Layer code.                                    ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;----------------------------------------------------------
; x_layer0(int y, void *ptr);
; Draw map out of tiles. No _shadowing & transparency
; supported here. BUT ITS FAST.
;----------------------------------------------------------
proc    x_layer0, data:ptr, y:dword

	push	esi
	push	edi
	push	ebp

; Calculate starting tile.
	mov	eax, [y]
	mov	ecx, eax		; Calculate [y] mod 32...
	and	ecx, 1fh		; ...and keep result in ecx for later use.
	shr	ax, 5                   ; Divide [y] by 32.
	imul	ax, XTILES		; XTILES=Number of tiles in x direction.
	movzx	ebx, ax			; Yes. Start Tile number in ebx now.
	shl	ebx, 2                  ; *4 to get index to pointer array.
	add	ebx, [data]             ; Add data offset.
; --> Now: ebx holds a pointer into the MAP POINTER ARRAY.

; Calculate offset into virtual screen.
; edi is offset pointer.
	mov	edi, YMAX-TILEYS
	add	edi, ecx		; Add precalculated value.
	imul	edi, LINEBYTES
        mov     edx, [vscreen]          ; Load pointer to virtual screen.
	mov	ebp, edi		; Backup edi.

; Coolness Part I: We are drawing the bottom tile row.
	mov	ch, XTILES		; Number of tiles to draw.

@@loop02:
	mov	esi, [ebx]		; Get pointer to tile data.
	add	ebx, 4			; Increment pointer to next tile.
        or      esi, esi
        jz      @@skip00

@@loop01:

I=0
rept    4
        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     [edi+edx+PLANESIZE*I+0], eax
	mov	eax, [esi]
	add	esi, 4
        mov     [edi+edx+PLANESIZE*I+4], eax
I=I+1
endm
        add     edi, LINEBYTES          ; Adjust pointer to next scan line.
	cmp	edi, PLANESIZE		; Out of screen ?
	jb	@@loop01		; Don't jump if done with this tile.

; Up to the next tile.
@@skip00:
        add     ebp, 8                  ; Adjust pointers.
	mov	edi, ebp
	dec	ch
	jnz	@@loop02

; Coolness Part II: Drawing tiles that don't have to be clipped.
@@loop12:
        sub     ebp, TILEYS*LINEBYTES+XTILES*8
	mov	edi, ebp
        jbe     @@part3                 ;Jump if reached top of screen.

	mov	ch, XTILES
@@loop11:
	mov	esi, [ebx]
	add	ebx, 4
        or      esi, esi
        jz      @@skip10
        mov     cl, TILEYS

@@loop10:
I=0
rept    4
        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     [edi+edx+PLANESIZE*I+0], eax
	mov	eax, [esi]
	add	esi, 4
        mov     [edi+edx+PLANESIZE*I+4], eax
I=I+1
endm
        add     edi, LINEBYTES          ; Adjust pointer to next scan line.
	dec	cl
	jnz	@@loop10

@@skip10:
	add	ebp, 8			; Move pointer to next tile in row.
	mov	edi, ebp
	dec	ch
	jnz	@@loop11

	jmp	@@loop12

; Coolness Part III: Drawing Top tile row.
@@part3:
	add	ebp, (TILEYS-1)*LINEBYTES
	mov	edi, ebp
	jl	@@done
	mov	ch, XTILES
@@loop31:
	mov	esi, [ebx]
	add	ebx, 4
        or      esi, esi
        jz      @@skip20
        add     esi, (TILEYS-1)*TILEXS

@@loop30:
I=0
rept    4
        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     [edi+edx+PLANESIZE*I+0], eax
	mov	eax, [esi]
	add	esi, 4
        mov     [edi+edx+PLANESIZE*I+4], eax
I=I+1
endm
        sub     esi, 2*TILEXS
        sub     edi, LINEBYTES
	jge	@@loop30

@@skip20:
	add	ebp, 8
	mov	edi, ebp
	dec	ch
	jne	@@loop31

@@done:
	pop	ebp
	pop	edi
	pop	esi

	ret

endp    x_layer0


;----------------------------------------------------------
; x_layer1(int y, void *ptr);
; Draw map out of tiles. Only transparency is
; supported here. No _shadowS yet.
; IT'S NOT AS FAST AS x_layer0.
;
; Tile data pointer:
; 0    : don't draw tile
; -1   : tile is _shadow
; other: valid pointer to tile data.
;----------------------------------------------------------
proc    x_layer1, data:ptr, y:dword

	push	esi
	push	edi
	push	ebp

; Calculate starting tile.
	mov	eax, [y]
	mov	ecx, eax		; Calculate [y] mod 32...
	and	ecx, 1fh		; ...and keep result in ecx for later use.
	shr	ax, 5                   ; Divide [y] by 32.
	imul	ax, XTILES		; XTILES=Number of tiles in x direction.
	movzx	ebx, ax			; Yes. Start Tile number in ebx now.
	shl	ebx, 2                  ; *4 to get index to pointer array.
	add	ebx, [data]             ; Add data offset.
; --> Now: ebx holds a pointer into the MAP POINTER ARRAY.

; Calculate offset into virtual screen.
; edi is offset pointer.
	mov	edi, YMAX-TILEYS
	add	edi, ecx		; Add precalculated value.
	imul	edi, LINEBYTES
        mov     edx, [vscreen]           ; Load pointer to virtual screen.
	mov	ebp, edi		; Backup edi.

; Coolness Part I: We are drawing the bottom tile row.
	mov	ch, XTILES		; Number of tiles to draw.

@@loop02:
	mov	esi, [ebx]		; Get pointer to tile data.
	add	ebx, 4			; Increment pointer to next tile.
        or      esi, esi                ; Check for empty tile.
        jz      @@skip00

        push    ebx                     ; Not very good. But no time to improve.

@@loop01:
I=0
rept 4
local   @@n0, @@n1, @@n2, @@n3, @@n4, @@n5, @@n6, @@n7

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+0]
        or      al, al
        jz      @@n0
        cmp     al, 0ffh
        je      @@n0
        mov     bl, al
@@n0:
        or      ah, ah
        jz      @@n1
        cmp     ah, 0ffh
        je      @@n1
        mov     bh, ah
@@n1:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n2
        cmp     al, 0ffh
        je      @@n2
        mov     bl, al
@@n2:
        or      ah, ah
        jz      @@n3
        cmp     ah, 0ffh
        je      @@n3
        mov     bh, ah
@@n3:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+0], ebx

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+4]
        or      al, al
        jz      @@n4
        cmp     al, 0ffh
        je      @@n4
        mov     bl, al
@@n4:
        or      ah, ah
        jz      @@n5
        cmp     ah, 0ffh
        je      @@n5
        mov     bh, ah
@@n5:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n6
        cmp     al, 0ffh
        je      @@n6
        mov     bl, al
@@n6:
        or      ah, ah
        jz      @@n7
        cmp     ah, 0ffh
        je      @@n7
        mov     bh, ah
@@n7:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+4], ebx
I=I+1
endm

        add     edi, LINEBYTES          ; Adjust pointer to next scan line.
	cmp	edi, PLANESIZE		; Out of screen ?
	jb	@@loop01		; Don't jump if done with this tile.
        pop     ebx

; Up to the next tile.
@@skip00:
	add	ebp, 8			; Adjust pointers.
	mov	edi, ebp
	dec	ch
	jnz	@@loop02

; Coolness Part II: Drawing tiles that don't have to be clipped.
@@loop12:
        sub     ebp, TILEYS*LINEBYTES+XTILES*8
	mov	edi, ebp
        jbe     @@part3                 ;Jump if reached top of screen.

	mov	ch, XTILES
@@loop11:
	mov	esi, [ebx]
	add	ebx, 4
        or      esi, esi
        jz      @@skip10

        push    ebx
        mov     cl, TILEYS
@@loop10:
I=0
rept 4
local   @@n0, @@n1, @@n2, @@n3, @@n4, @@n5, @@n6, @@n7

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+0]
        or      al, al
        jz      @@n0
        cmp     al, 0ffh
        je      @@n0
        mov     bl, al
@@n0:
        or      ah, ah
        jz      @@n1
        cmp     ah, 0ffh
        je      @@n1
        mov     bh, ah
@@n1:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n2
        cmp     al, 0ffh
        je      @@n2
        mov     bl, al
@@n2:
        or      ah, ah
        jz      @@n3
        cmp     ah, 0ffh
        je      @@n3
        mov     bh, ah
@@n3:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+0], ebx

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+4]
        or      al, al
        jz      @@n4
        cmp     al, 0ffh
        je      @@n4
        mov     bl, al
@@n4:
        or      ah, ah
        jz      @@n5
        cmp     ah, 0ffh
        je      @@n5
        mov     bh, ah
@@n5:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n6
        cmp     al, 0ffh
        je      @@n6
        mov     bl, al
@@n6:
        or      ah, ah
        jz      @@n7
        cmp     ah, 0ffh
        je      @@n7
        mov     bh, ah
@@n7:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+4], ebx
I=I+1
endm
        add     edi, LINEBYTES          ; Move pointer to next scan line.
	dec	cl
	jnz	@@loop10
        pop     ebx

@@skip10:
	add	ebp, 8			; Move pointer to next tile in row.
	mov	edi, ebp
	dec	ch
	jnz	@@loop11

	jmp	@@loop12

; Coolness Part III: Drawing Top tile row.
@@part3:
	add	ebp, (TILEYS-1)*LINEBYTES
	mov	edi, ebp
	jl	@@done
	mov	ch, XTILES
@@loop31:
	mov	esi, [ebx]
	add	ebx, 4
        or      esi, esi
        jz      @@skip20

        push    ebx

        add     esi, (TILEYS-1)*TILEXS

@@loop30:
I=0
rept 4
local   @@n0, @@n1, @@n2, @@n3, @@n4, @@n5, @@n6, @@n7

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+0]
        or      al, al
        jz      @@n0
        cmp     al, 0ffh
        je      @@n0
        mov     bl, al
@@n0:
        or      ah, ah
        jz      @@n1
        cmp     ah, 0ffh
        je      @@n1
        mov     bh, ah
@@n1:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n2
        cmp     al, 0ffh
        je      @@n2
        mov     bl, al
@@n2:
        or      ah, ah
        jz      @@n3
        cmp     ah, 0ffh
        je      @@n3
        mov     bh, ah
@@n3:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+0], ebx

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+4]
        or      al, al
        jz      @@n4
        cmp     al, 0ffh
        je      @@n4
        mov     bl, al
@@n4:
        or      ah, ah
        jz      @@n5
        cmp     ah, 0ffh
        je      @@n5
        mov     bh, ah
@@n5:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n6
        cmp     al, 0ffh
        je      @@n6
        mov     bl, al
@@n6:
        or      ah, ah
        jz      @@n7
        cmp     ah, 0ffh
        je      @@n7
        mov     bh, ah
@@n7:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+4], ebx
I=I+1
endm
	sub	esi, 2*TILEXS
        sub     edi, LINEBYTES
	jge	@@loop30
        pop     ebx

@@skip20:
	add	ebp, 8
	mov	edi, ebp
	dec	ch
	jne	@@loop31

@@done:
	pop	ebp
	pop	edi
	pop	esi

	ret

endp    x_layer1

;----------------------------------------------------------
; x_layer2(int y, void *ptr);
; Draw map out of tiles. _shadowing & transparency is
; supported here. IT'S EVEN SLOWER THAN x_layer1.
;
; Tile data pointer:
; 0    : don't draw tile
; -1   : tile is _shadow
; other: valid pointer to tile data.
;----------------------------------------------------------
proc    x_layer2, data:ptr, y:dword

	push	esi
	push	edi
	push	ebp

; Calculate starting tile.
	mov	eax, [y]
	mov	ecx, eax		; Calculate [y] mod 32...
	and	ecx, 1fh		; ...and keep result in ecx for later use.
	shr	ax, 5                   ; Divide [y] by 32.
	imul	ax, XTILES		; XTILES=Number of tiles in x direction.
	movzx	ebx, ax			; Yes. Start Tile number in ebx now.
	shl	ebx, 2                  ; *4 to get index to pointer array.
	add	ebx, [data]             ; Add data offset.
; --> Now: ebx holds a pointer into the MAP POINTER ARRAY.

; Calculate offset into virtual screen.
; edi is offset pointer.
	mov	edi, YMAX-TILEYS
	add	edi, ecx		; Add precalculated value.
	imul	edi, LINEBYTES
        mov     edx, [vscreen]           ; Load pointer to virtual screen.
	mov	ebp, edi		; Backup edi.

; Coolness Part I: We are drawing the bottom tile row.
	mov	ch, XTILES		; Number of tiles to draw.

@@loop02:
	mov	esi, [ebx]		; Get pointer to tile data.
	add	ebx, 4			; Increment pointer to next tile.
        or      esi, esi                ; Check for empty tile.
        jz      @@skip00

        push    ecx
        push    ebx                     ; Not very good. But no time to improve.
        xor     ecx, ecx

@@loop01:
I=0
rept 4
local   @@n0, @@n1, @@n2, @@n3, @@n4, @@n5, @@n6, @@n7
local   @@ns0, @@ns1, @@ns2, @@ns3, @@ns4, @@ns5, @@ns6, @@ns7

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+0]
        or      al, al
        jz      @@n0
        cmp     al, 0ffh
        jne     @@ns0
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns0:
        mov     bl, al
@@n0:
        or      ah, ah
        jz      @@n1
        cmp     ah, 0ffh
        jne     @@ns1
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns1:
        mov     bh, ah
@@n1:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n2
        cmp     al, 0ffh
        jne     @@ns2
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns2:
        mov     bl, al
@@n2:
        or      ah, ah
        jz      @@n3
        cmp     ah, 0ffh
        jne     @@ns3
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns3:
        mov     bh, ah
@@n3:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+0], ebx

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+4]
        or      al, al
        jz      @@n4
        cmp     al, 0ffh
        jne     @@ns4
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns4:
        mov     bl, al
@@n4:
        or      ah, ah
        jz      @@n5
        cmp     ah, 0ffh
        jne     @@ns5
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns5:
        mov     bh, ah
@@n5:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n6
        cmp     al, 0ffh
        jne     @@ns6
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns6:
        mov     bl, al
@@n6:
        or      ah, ah
        jz      @@n7
        cmp     ah, 0ffh
        jne     @@ns7
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns7:
        mov     bh, ah
@@n7:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+4], ebx
I=I+1
endm

        add     edi, LINEBYTES          ; Adjust pointer to next scan line.
	cmp	edi, PLANESIZE		; Out of screen ?
	jb	@@loop01		; Don't jump if done with this tile.
@@sdone0:
        pop     ebx
        pop     ecx

; Up to the next tile.
@@skip00:
	add	ebp, 8			; Adjust pointers.
	mov	edi, ebp
	dec	ch
	jnz	@@loop02

; Coolness Part II: Drawing tiles that don't have to be clipped.
@@loop12:
        sub     ebp, TILEYS*LINEBYTES+XTILES*8
	mov	edi, ebp
        jbe     @@part3                 ;Jump if reached top of screen.

	mov	ch, XTILES
@@loop11:
	mov	esi, [ebx]
	add	ebx, 4
        or      esi, esi
        jz      @@skip10

        push    ebx
        mov     cl, TILEYS

@@loop10:
        push    ecx
        xor     ecx, ecx
I=0
rept 4
local   @@n0, @@n1, @@n2, @@n3, @@n4, @@n5, @@n6, @@n7
local   @@ns0, @@ns1, @@ns2, @@ns3, @@ns4, @@ns5, @@ns6, @@ns7

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+0]
        or      al, al
        jz      @@n0
        cmp     al, 0ffh
        jne     @@ns0
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns0:
        mov     bl, al
@@n0:
        or      ah, ah
        jz      @@n1
        cmp     ah, 0ffh
        jne     @@ns1
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns1:
        mov     bh, ah
@@n1:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n2
        cmp     al, 0ffh
        jne     @@ns2
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns2:
        mov     bl, al
@@n2:
        or      ah, ah
        jz      @@n3
        cmp     ah, 0ffh
        jne     @@ns3
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns3:
        mov     bh, ah
@@n3:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+0], ebx

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+4]
        or      al, al
        jz      @@n4
        cmp     al, 0ffh
        jne     @@ns4
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns4:
        mov     bl, al
@@n4:
        or      ah, ah
        jz      @@n5
        cmp     ah, 0ffh
        jne     @@ns5
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns5:
        mov     bh, ah
@@n5:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n6
        cmp     al, 0ffh
        jne     @@ns6
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns6:
        mov     bl, al
@@n6:
        or      ah, ah
        jz      @@n7
        cmp     ah, 0ffh
        jne     @@ns7
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns7:
        mov     bh, ah
@@n7:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+4], ebx
I=I+1
endm

        pop     ecx
        add     edi, LINEBYTES          ; Move pointer to next scan line.
	dec	cl
	jnz	@@loop10
@@sdone1:
        pop     ebx

@@skip10:
	add	ebp, 8			; Move pointer to next tile in row.
	mov	edi, ebp
	dec	ch
	jnz	@@loop11

	jmp	@@loop12

; Coolness Part III: Drawing Top tile row.
@@part3:
	add	ebp, (TILEYS-1)*LINEBYTES
	mov	edi, ebp
	jl	@@done
	mov	ch, XTILES
@@loop31:
	mov	esi, [ebx]
	add	ebx, 4
        or      esi, esi
        jz      @@skip20

        push    ebx
        add     esi, (TILEYS-1)*TILEXS
        push    ecx
        xor     ecx, ecx

@@loop30:
I=0
rept 4
local   @@n0, @@n1, @@n2, @@n3, @@n4, @@n5, @@n6, @@n7
local   @@ns0, @@ns1, @@ns2, @@ns3, @@ns4, @@ns5, @@ns6, @@ns7

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+0]
        or      al, al
        jz      @@n0
        cmp     al, 0ffh
        jne     @@ns0
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns0:
        mov     bl, al
@@n0:
        or      ah, ah
        jz      @@n1
        cmp     ah, 0ffh
        jne     @@ns1
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns1:
        mov     bh, ah
@@n1:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n2
        cmp     al, 0ffh
        jne     @@ns2
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns2:
        mov     bl, al
@@n2:
        or      ah, ah
        jz      @@n3
        cmp     ah, 0ffh
        jne     @@ns3
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns3:
        mov     bh, ah
@@n3:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+0], ebx

        mov     eax, [esi]              ; Load tile data.
	add	esi, 4			; Increment to next data dword.
        mov     ebx, [edi+edx+PLANESIZE*I+4]
        or      al, al
        jz      @@n4
        cmp     al, 0ffh
        jne     @@ns4
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns4:
        mov     bl, al
@@n4:
        or      ah, ah
        jz      @@n5
        cmp     ah, 0ffh
        jne     @@ns5
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns5:
        mov     bh, ah
@@n5:
        ror     eax, 16
        ror     ebx, 16
        or      al, al
        jz      @@n6
        cmp     al, 0ffh
        jne     @@ns6
        mov     cl, bl
        mov     al, [byte _shadow + ecx]
@@ns6:
        mov     bl, al
@@n6:
        or      ah, ah
        jz      @@n7
        cmp     ah, 0ffh
        jne     @@ns7
        mov     cl, bh
        mov     ah, [byte _shadow + ecx]
@@ns7:
        mov     bh, ah
@@n7:
        ror     ebx, 16
        mov     [edi+edx+PLANESIZE*I+4], ebx
I=I+1
endm
	sub	esi, 2*TILEXS
        sub     edi, LINEBYTES
	jge	@@loop30
@@sdone2:
        pop     ecx
        pop     ebx

@@skip20:
	add	ebp, 8
	mov	edi, ebp
	dec	ch
	jne	@@loop31

@@done:
	pop	ebp
	pop	edi
	pop	esi

	ret

endp    x_layer2


        end


